﻿using CloudFranceTriple.Models;
using CloudFranceTriple.WebRole.Filters;
using CloudFranceTriple.WebRole.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;

namespace CloudFranceTriple.WebRole
{
    [InitializeSimpleMembership]
    public class BaseController : Controller
    {
        private cloudfrAboq2RsDMEntities db = new cloudfrAboq2RsDMEntities();

        private readonly IWebSecurityWrapper _webSecurity;
        public BaseController()
        {
            this._webSecurity = new WebSecurityWrapper();
        }

        public BaseController(IWebSecurityWrapper webSecurity)
        {
            this._webSecurity = webSecurity;
        }

        protected String UserGravatarHash
        {
            get
            {
                if (!User.Identity.IsAuthenticated)
                    return "notfound";

                var source = GetProfile().Gravatar.Trim().ToLower();
                string hash;

                using (MD5 md5Hash = MD5.Create())
                {
                    hash = GetMd5Hash(md5Hash, source);
                    if (!VerifyMd5Hash(md5Hash, source, hash))
                    {
                        //throw new ApplicationException("Gravatar MD5 hash encoding exception.");
                        return "notfound";
                    }
                }
                return hash;
            }
        }
        protected String UserGravatarHashByUserId(Int32 userId)
        {

            var source = GetProfile(userId).Gravatar.Trim().ToLower();
            string hash;

            using (MD5 md5Hash = MD5.Create())
            {
                hash = GetMd5Hash(md5Hash, source);
                if (!VerifyMd5Hash(md5Hash, source, hash))
                {
                    //throw new ApplicationException("Gravatar MD5 hash encoding exception.");
                    return "notfound";
                }
            }
            return hash;
        }
        protected static string GetMd5Hash(MD5 md5Hash, string input)
        {
            // Convert the input string to a byte array and compute the hash. 
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes 
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data  
            // and format each one as a hexadecimal string. 
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string. 
            return sBuilder.ToString();
        }

        // Verify a hash against a string. 
        protected static bool VerifyMd5Hash(MD5 md5Hash, string input, string hash)
        {
            // Hash the input. 
            string hashOfInput = GetMd5Hash(md5Hash, input);

            // Create a StringComparer an compare the hashes.
            StringComparer comparer = StringComparer.OrdinalIgnoreCase;
            if (0 == comparer.Compare(hashOfInput, hash))
                return true;
            else
                return false;
        }

        protected Int32 UserId
        {
            get
            {
                return GetProfile().UserId;
            }
        }
        protected List<Int32> ForumIdAllowed
        {
            get
            {
                return _forumIdAllowed(User.Identity.IsAuthenticated);
            }
        }

        protected List<Int32> ForumCategoryAllowed
        {
            get
            {
                return db.ForumCategorySet.Where(cat => ForumIdAllowed.Contains(cat.Forum_Id)).Select(cat2 => cat2.Id).ToList();
            }
        }
        protected List<Int32> ForumTopicAllowed
        {
            get
            {
                return db.ForumTopicSet.Where(topic => ForumCategoryAllowed.Contains(topic.ForumCategory_Id)).Select(topic2 => topic2.Id).ToList();
            }
        }

        protected List<Int32> ForumPostAllowed
        {
            get
            {
                return db.ForumPostSet.Where(post => ForumTopicAllowed.Contains(post.ForumTopic_Id)).Select(post2 => post2.Id).ToList();
            }
        }
        protected List<Int32> ForumPostUnread
        {
            get
            {
                var query = db.ForumPostSet.Where(post => ForumTopicAllowed.Contains(post.ForumTopic_Id)).Except(db.ForumPostSet.Where(post => post.ForumPostReadSet.Where(read => read.UserId == UserId).Count() > 0)).Select(post => post.Id).ToList();

                return query;
            }
        }
        /// <summary>
        /// Accéder aux champs personalisés du profile utilisateur
        /// </summary>
        /// <returns></returns>
        public CloudFranceTriple.WebRole.Models.UserProfile GetProfile()
        {
            return GetProfile(User.Identity.Name);
        }
        /// <summary>
        /// Accéder aux champs personalisés du profile utilisateur
        /// </summary>
        /// <returns></returns>
        public CloudFranceTriple.WebRole.Models.UserProfile GetProfile(String username)
        {
            var context = new UsersContext();
            return context.UserProfiles.SingleOrDefault(u => u.UserName == username);
        }
        /// <summary>
        /// Accéder aux champs personalisés du profile utilisateur
        /// </summary>
        /// <returns></returns>
        public CloudFranceTriple.WebRole.Models.UserProfile GetProfile(Int32 userId)
        {
            var context = new UsersContext();
            return context.UserProfiles.Find(userId);
        }
        protected void ThrowSecurityException()
        {
            throw new HttpException(403, "Operation not allowed and called without using ActionLink.");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="forumtopicset"></param>
        /// <returns></returns>
        protected Boolean CheckAutorRights(ForumTopicSet forumtopicset)
        {
            if ((User.Identity.Name.ToLower() == forumtopicset.AuthorForumTopic.ToLower()) || User.IsInRole("RoleAdminForum"))
                return true;
            else
                return false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="forumtopicset"></param>
        protected void ThrowSecurityException(ForumTopicSet forumtopicset)
        {
            //HttpException(403,"Operation not allowed and called without using ActionLink.");
            throw new HttpException(403,
                    String.Format("Operation not allowed and called without using ActionLink.<br />id : {0}<br />ForumCategory_Id : {1}<br />LabelForumTopic : {2}<br />AuthorForumTopic : {3}",
                    forumtopicset.Id,
                    forumtopicset.ForumCategory_Id,
                     HttpUtility.HtmlDecode(forumtopicset.LabelForumTopic),
                     HttpUtility.HtmlDecode(forumtopicset.AuthorForumTopic)));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="forumpostset"></param>
        /// <returns></returns>
        protected Boolean CheckAutorRights(ForumPostSet forumpostset)
        {
            if ((User.Identity.Name.ToLower() == forumpostset.PostMessage_Author.ToLower()) || User.IsInRole("RoleAdminForum"))
                return true;
            else
                return false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="forumpostset"></param>
        protected void ThrowSecurityException(ForumPostSet forumpostset)
        {
            //HttpException(403,"Operation not allowed and called without using ActionLink.");
            throw new HttpException(403,
                    String.Format("Operation not allowed and called without using ActionLink.<br />id : {0}<br />PostMessage_Message : {1}<br />PostMessage_Author : {2}<br />PostMessage_CreationDate : {3}<br />PostMessage_AuthorAdressIp : {4}",
                    forumpostset.Id,
                    forumpostset.PostMessage_Message,
                    forumpostset.PostMessage_Author,
                    forumpostset.PostMessage_CreationDate,
                    forumpostset.PostMessage_AuthorAdressIp));
        }
        /// <summary>
        /// List<Int32> des ForumSet.Id autorisés pour l'utilisateur courant
        /// </summary>
        private List<Int32> _forumIdAllowed(Boolean IsAuthenticated)
        {
            var db = new cloudfrAboq2RsDMEntities();
            // Cas des administrateurs : accès total
            if (IsAuthenticated && User.IsInRole("RoleAdminForum"))
                return (from f in db.ForumSet
                        orderby f.OrderForum
                        select f.Id).ToList();
            // Cas des utilisateurs authentifiés et des utilisateurs anonymes
            else
            {
                String[] UserRoles = Roles.GetRolesForUser();
                if (!IsAuthenticated | UserRoles.Count() == 0)
                    UserRoles = new String[1] { "RolePublic" };

                return (from r in db.webpages_Roles
                        from rf in r.ForumSecuritySet
                        where r.RoleId == rf.webpages_Roles_RoleId
                        & UserRoles.Contains(r.RoleName)
                        select rf.ForumSet_Id).ToList();
            }
        }
        /// <summary>
        /// Niveau d'autorisation pour un utilisateur sur un forum par TopicId
        /// </summary>
        /// <param name="TopicId"></param>
        /// <param name="IsAuthenticated"></param>
        /// <returns></returns>
        public Int32 UserRightLevelByTopicId(Int32 TopicId, Boolean IsAuthenticated)
        {
            Int32 ForumId = db.ForumCategorySet.Find(db.ForumTopicSet.Find(TopicId).ForumCategory_Id).Forum_Id;
            return UserRightLevelByForumId(ForumId, IsAuthenticated);
        }
        /// <summary>
        /// Niveau d'autorisation pour un utilisateur sur un forum par CategoryId
        /// </summary>
        /// <param name="ForumId"></param>
        /// <returns></returns>
        public Int32 UserRightLevelByCategoryId(Int32 CategoryId, Boolean IsAuthenticated)
        {
            Int32 ForumId = db.ForumCategorySet.Find(CategoryId).Forum_Id;
            return UserRightLevelByForumId(ForumId, IsAuthenticated);
        }
        /// <summary>
        /// Niveau d'autorisation pour un utilisateur sur un forum par ForumId
        /// 1 : Lecture
        /// 2 : Auteur
        /// 3 : Modérateur
        /// </summary>
        /// <param name="ForumId"></param>
        /// <returns></returns>
        public Int32 UserRightLevelByForumId(Int32 ForumId, Boolean IsAuthenticated)
        {
            // Cas des administrateurs : accès total
            if (IsAuthenticated && User.IsInRole("RoleAdminForum"))
                return RightLevel.Moderator;
            else
            {
                String[] UserRoles = Roles.GetRolesForUser();
                if (!IsAuthenticated | UserRoles.Count() == 0)
                    UserRoles = new String[1] { "RolePublic" };

                return (from r in db.webpages_Roles
                        from rf in r.ForumSecuritySet
                        where r.RoleId == rf.webpages_Roles_RoleId
                        & rf.ForumSet_Id == ForumId
                        & UserRoles.Contains(r.RoleName)
                        select rf.RightLevel).DefaultIfEmpty().Max();
            }
        }

        public Int32 UserRightLevelByForumId(Int32 ForumId, IPrincipal User)
        {
            // Cas des administrateurs : accès total
            if (User.Identity.IsAuthenticated && User.IsInRole("RoleAdminForum"))
                return RightLevel.Moderator;
            else
            {
                String[] UserRoles = Roles.GetRolesForUser();
                if (!User.Identity.IsAuthenticated | UserRoles.Count() == 0)
                    UserRoles = new String[1] { "RolePublic" };

                return (from r in db.webpages_Roles
                        from rf in r.ForumSecuritySet
                        where r.RoleId == rf.webpages_Roles_RoleId
                        & rf.ForumSet_Id == ForumId
                        & UserRoles.Contains(r.RoleName)
                        select rf.RightLevel).DefaultIfEmpty().Max();
            }
        }
        protected static List<SelectListItem> GetTimeZoneSelectList()
        {
            return new List<SelectListItem>
            {
                new SelectListItem{Value="Dateline Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone1},
                    new SelectListItem{Value="UTC-11",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone2},
                    new SelectListItem{Value="Hawaiian Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone3},
                    new SelectListItem{Value="Alaskan Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone4},
                    new SelectListItem{Value="Pacific Standard Time (Mexico)",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone5},
                    new SelectListItem{Value="Pacific Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone6},
                    new SelectListItem{Value="US Mountain Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone7},
                    new SelectListItem{Value="Mountain Standard Time (Mexico)",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone8},
                    new SelectListItem{Value="Mountain Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone9},
                    new SelectListItem{Value="Central America Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone10},
                    new SelectListItem{Value="Central Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone11},
                    new SelectListItem{Value="Central Standard Time (Mexico)",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone12},
                    new SelectListItem{Value="Canada Central Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone13},
                    new SelectListItem{Value="SA Pacific Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone14},
                    new SelectListItem{Value="Eastern Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone15},
                    new SelectListItem{Value="US Eastern Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone16},
                    new SelectListItem{Value="Venezuela Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone17},
                    new SelectListItem{Value="Paraguay Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone18},
                    new SelectListItem{Value="Atlantic Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone19},
                    new SelectListItem{Value="Central Brazilian Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone20},
                    new SelectListItem{Value="SA Western Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone21},
                    new SelectListItem{Value="Pacific SA Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone22},
                    new SelectListItem{Value="Newfoundland Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone23},
                    new SelectListItem{Value="E. South America Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone24},
                    new SelectListItem{Value="Argentina Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone25},
                    new SelectListItem{Value="SA Eastern Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone26},
                    new SelectListItem{Value="Greenland Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone27},
                    new SelectListItem{Value="Montevideo Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone28},
                    new SelectListItem{Value="Bahia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone29},
                    new SelectListItem{Value="UTC-02",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone30},
                    new SelectListItem{Value="Mid-Atlantic Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone31},
                    new SelectListItem{Value="Azores Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone32},
                    new SelectListItem{Value="Cape Verde Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone33},
                    new SelectListItem{Value="Morocco Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone34},
                    new SelectListItem{Value="UTC",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone35},
                    new SelectListItem{Value="GMT Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone36},
                    new SelectListItem{Value="Greenwich Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone37},
                    new SelectListItem{Value="W. Europe Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone38},
                    new SelectListItem{Value="Central Europe Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone39},
                    new SelectListItem{Value="Romance Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone40},
                    new SelectListItem{Value="Central European Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone41},
                    new SelectListItem{Value="W. Central Africa Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone42},
                    new SelectListItem{Value="Namibia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone43},
                    new SelectListItem{Value="GTB Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone44},
                    new SelectListItem{Value="Middle East Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone45},
                    new SelectListItem{Value="Egypt Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone46},
                    new SelectListItem{Value="Syria Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone47},
                    new SelectListItem{Value="E. Europe Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone48},
                    new SelectListItem{Value="South Africa Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone49},
                    new SelectListItem{Value="FLE Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone50},
                    new SelectListItem{Value="Turkey Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone51},
                    new SelectListItem{Value="Israel Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone52},
                    new SelectListItem{Value="Jordan Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone53},
                    new SelectListItem{Value="Arabic Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone54},
                    new SelectListItem{Value="Kaliningrad Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone55},
                    new SelectListItem{Value="Arab Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone56},
                    new SelectListItem{Value="E. Africa Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone57},
                    new SelectListItem{Value="Iran Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone58},
                    new SelectListItem{Value="Arabian Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone59},
                    new SelectListItem{Value="Azerbaijan Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone60},
                    new SelectListItem{Value="Russian Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone61},
                    new SelectListItem{Value="Mauritius Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone62},
                    new SelectListItem{Value="Georgian Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone63},
                    new SelectListItem{Value="Caucasus Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone64},
                    new SelectListItem{Value="Afghanistan Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone65},
                    new SelectListItem{Value="Pakistan Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone66},
                    new SelectListItem{Value="West Asia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone67},
                    new SelectListItem{Value="India Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone68},
                    new SelectListItem{Value="Sri Lanka Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone69},
                    new SelectListItem{Value="Nepal Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone70},
                    new SelectListItem{Value="Central Asia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone71},
                    new SelectListItem{Value="Bangladesh Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone72},
                    new SelectListItem{Value="Ekaterinburg Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone73},
                    new SelectListItem{Value="Myanmar Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone74},
                    new SelectListItem{Value="SE Asia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone75},
                    new SelectListItem{Value="N. Central Asia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone76},
                    new SelectListItem{Value="China Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone77},
                    new SelectListItem{Value="North Asia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone78},
                    new SelectListItem{Value="Singapore Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone79},
                    new SelectListItem{Value="W. Australia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone80},
                    new SelectListItem{Value="Taipei Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone81},
                    new SelectListItem{Value="Ulaanbaatar Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone82},
                    new SelectListItem{Value="North Asia East Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone83},
                    new SelectListItem{Value="Tokyo Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone84},
                    new SelectListItem{Value="Korea Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone85},
                    new SelectListItem{Value="Cen. Australia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone86},
                    new SelectListItem{Value="AUS Central Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone87},
                    new SelectListItem{Value="E. Australia Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone88},
                    new SelectListItem{Value="AUS Eastern Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone89},
                    new SelectListItem{Value="West Pacific Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone90},
                    new SelectListItem{Value="Tasmania Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone91},
                    new SelectListItem{Value="Yakutsk Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone92},
                    new SelectListItem{Value="Central Pacific Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone93},
                    new SelectListItem{Value="Vladivostok Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone94},
                    new SelectListItem{Value="New Zealand Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone95},
                    new SelectListItem{Value="UTC+12",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone96},
                    new SelectListItem{Value="Fiji Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone97},
                    new SelectListItem{Value="Magadan Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone98},
                    new SelectListItem{Value="Kamchatka Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone99},
                    new SelectListItem{Value="Tonga Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone100},
                    new SelectListItem{Value="Samoa Standard Time",Text=CloudFranceTriple.WebRole.Properties.Resources.TimeZone101},              
            };
        }

        private void ConvertTopicsDateToUserTimeZone(ref List<TopicResult> query)
        {
            var userTimeZoneInfo = Extension.GetUserTimeZoneInfo(_webSecurity.CurrentUserId);
            foreach (TopicResult topic in query)
            {
                topic.CreationDateForumTopic = topic.CreationDateForumTopic.ToUserTimeZone(userTimeZoneInfo);
                topic.LastPostDate = topic.LastPostDate.ToUserTimeZone(userTimeZoneInfo);
            }
        }
        /// <summary>
        /// Liste des sujets contenant les "postQuantity" derniers posts
        /// </summary>
        /// <param name="postQuantity"></param>
        /// <param name="requesterTimeZone"></param>
        /// <returns></returns>
        protected List<TopicResult> GetForumLastNPost(Int32 postQuantity = 10000)
        {
            List<TopicResult> query;

            query = (from t in db.vw_ForumLastTopic
                     where ForumIdAllowed.Contains(t.ForumId)
                     orderby t.LastPostDate descending
                     select new TopicResult()
                     {
                         Id = t.Id,
                         Label = t.Label,
                         Author = t.Author,
                         NumberHasBeenSeen = t.NumberHasBeenSeen,
                         IsUnlocked = t.IsUnlocked,
                         OrderForumTopic = t.OrderForumTopic,
                         CreationDateForumTopic = t.CreationDateForumTopic,
                         NumberOfPost = t.NumberOfPost ?? 0,
                         LastPostDate = (t.LastPostDate ?? new DateTime()),
                         LastPostAuthor = (from p in db.ForumPostSet where (p.Id == t.LastPostId) select p.PostMessage_Author).FirstOrDefault(),
                         LastPostTopicId = t.Id,
                         LastPostId = t.LastPostId ?? 0,
                         ForumCategoryId = t.ForumCategoryId,
                         ForumId = t.ForumId
                     }).Take(postQuantity).ToList();
            ConvertTopicsDateToUserTimeZone(ref query);
            return query;
        }
        /// <summary>
        /// Liste des sujet créé en dernier
        /// </summary>
        /// <param name="postQuantity"></param>
        /// <param name="requesterTimeZone"></param>
        /// <returns></returns>
        protected List<TopicResult> GetForumLastNTopics(Int32 postQuantity = 10000)
        {
            var query = (from t in db.vw_ForumLastTopic
                         where ForumIdAllowed.Contains(t.ForumId)
                         orderby t.CreationDateForumTopic descending
                         select new TopicResult()
                         {
                             Id = t.Id,
                             Label = t.Label,
                             Author = t.Author,
                             NumberHasBeenSeen = t.NumberHasBeenSeen,
                             IsUnlocked = t.IsUnlocked,
                             OrderForumTopic = t.OrderForumTopic,
                             CreationDateForumTopic = t.CreationDateForumTopic,
                             NumberOfPost = t.NumberOfPost ?? 0,
                             LastPostDate = (t.LastPostDate ?? new DateTime()),
                             LastPostAuthor = (from p in db.ForumPostSet where (p.Id == t.LastPostId) select p.PostMessage_Author).FirstOrDefault(),
                             LastPostTopicId = t.Id,
                             LastPostId = t.LastPostId ?? 0,
                             ForumCategoryId = t.ForumCategoryId,
                             ForumId = t.ForumId
                         }).Take(postQuantity).ToList();
            ConvertTopicsDateToUserTimeZone(ref query);
            return query;
        }
        /// <summary>
        /// Liste des sujets d'une catégorie
        /// </summary>
        /// <param name="CategoryId"></param>
        /// <param name="postQuantity"></param>
        /// <param name="requesterTimeZone"></param>
        /// <returns></returns>
        protected List<TopicResult> GetByCategoryNTopics(Int32 CategoryId, Int32 postQuantity = 10000)
        {
            List<TopicResult> query;

            query = db.vw_ForumLastTopic.Where(c1 => c1.ForumCategoryId == CategoryId).Where(c2 => ForumIdAllowed.Contains(c2.ForumId)).OrderByDescending(c2 => c2.OrderForumTopic).ThenByDescending(c3 => c3.CreationDateForumTopic).Select(t => new TopicResult()
            {
                Id = t.Id,
                Label = t.Label,
                Author = t.Author,
                NumberHasBeenSeen = t.NumberHasBeenSeen,
                IsUnlocked = t.IsUnlocked,
                OrderForumTopic = t.OrderForumTopic,
                CreationDateForumTopic = t.CreationDateForumTopic,
                NumberOfPost = t.NumberOfPost ?? 0,
                LastPostDate = (t.LastPostDate ?? new DateTime()),
                LastPostAuthor = (from p in db.ForumPostSet where (p.Id == t.LastPostId) select p.PostMessage_Author).FirstOrDefault(),
                LastPostTopicId = t.Id,
                LastPostId = t.LastPostId ?? 0,
                ForumCategoryId = t.ForumCategoryId,
                ForumId = t.ForumId
            }).Take(postQuantity).ToList();
            ConvertTopicsDateToUserTimeZone(ref query);
            return query;
        }
        /// <summary>
        /// Liste des sujets n'ayant pas de réponse, donc contenant zéro ou un message
        /// </summary>
        /// <param name="postQuantity"></param>
        /// <param name="requesterTimeZone"></param>
        /// <returns></returns>
        protected List<TopicResult> GetTopicsWithoutAnswer(Int32 postQuantity = 10000)
        {
            var topicsWithoutAnswer = db.ForumTopicSet.Where(topic => new Int32[2] { 0, 1 }.Contains(topic.ForumPostSet.Count())).Select(topic2 => topic2.Id);

            var query = (from t in db.vw_ForumLastTopic
                         where (ForumIdAllowed.Contains(t.ForumId) & topicsWithoutAnswer.Contains(t.Id))
                         orderby t.CreationDateForumTopic descending
                         select new TopicResult()
                         {
                             Id = t.Id,
                             Label = t.Label,
                             Author = t.Author,
                             NumberHasBeenSeen = t.NumberHasBeenSeen,
                             IsUnlocked = t.IsUnlocked,
                             OrderForumTopic = t.OrderForumTopic,
                             CreationDateForumTopic = t.CreationDateForumTopic,
                             NumberOfPost = t.NumberOfPost ?? 0,
                             LastPostDate = (t.LastPostDate ?? new DateTime()),
                             LastPostAuthor = (from p in db.ForumPostSet where (p.Id == t.LastPostId) select p.PostMessage_Author).FirstOrDefault(),
                             LastPostTopicId = t.Id,
                             LastPostId = t.LastPostId ?? 0,
                             ForumCategoryId = t.ForumCategoryId,
                             ForumId = t.ForumId
                         }).Take(postQuantity).ToList();
            ConvertTopicsDateToUserTimeZone(ref query);
            return query;
        }
        /// <summary>
        /// Liste des sujet non-lu par l'utilisateur courant.
        /// </summary>
        /// <param name="postQuantity"></param>
        /// <param name="requesterTimeZone"></param>
        /// <returns></returns>
        protected List<TopicResult> GetUnreadTopics(Int32 postQuantity = 10000)
        {
            var allowedTopics = ForumTopicAllowed;
            var allpostUnread = ForumPostUnread;

            var query = (from t in db.vw_ForumLastTopic
                         where allpostUnread.Contains(t.LastPostId ?? 0)
                         orderby t.LastPostDate descending
                         select new TopicResult()
                         {
                             Id = t.Id,
                             Label = t.Label,
                             Author = t.Author,
                             NumberHasBeenSeen = t.NumberHasBeenSeen,
                             IsUnlocked = t.IsUnlocked,
                             OrderForumTopic = t.OrderForumTopic,
                             CreationDateForumTopic = t.CreationDateForumTopic,
                             NumberOfPost = t.NumberOfPost ?? 0,
                             LastPostDate = (t.LastPostDate ?? new DateTime()),
                             LastPostAuthor = (from p in db.ForumPostSet where (p.Id == t.LastPostId) select p.PostMessage_Author).FirstOrDefault(),
                             LastPostTopicId = t.Id,
                             LastPostId = t.LastPostId ?? 0,
                             ForumCategoryId = t.ForumCategoryId,
                             ForumId = t.ForumId
                         }).Take(postQuantity).ToList();
            ConvertTopicsDateToUserTimeZone(ref query);
            return query;
        }

        /// <summary>
        /// Liste des sujet les plus vus.
        /// </summary>
        /// <param name="postQuantity"></param>
        /// <param name="requesterTimeZone"></param>
        /// <returns></returns>
        protected List<TopicResult> GetMostViewedTopics(Int32 postQuantity = 10000)
        {
            var query = (from t in db.vw_ForumLastTopic
                         where ForumIdAllowed.Contains(t.ForumId)
                         orderby t.NumberHasBeenSeen descending
                         select new TopicResult()
                         {
                             Id = t.Id,
                             Label = t.Label,
                             Author = t.Author,
                             NumberHasBeenSeen = t.NumberHasBeenSeen,
                             IsUnlocked = t.IsUnlocked,
                             OrderForumTopic = t.OrderForumTopic,
                             CreationDateForumTopic = t.CreationDateForumTopic,
                             NumberOfPost = t.NumberOfPost ?? 0,
                             LastPostDate = (t.LastPostDate ?? new DateTime()),
                             LastPostAuthor = (from p in db.ForumPostSet where (p.Id == t.LastPostId) select p.PostMessage_Author).FirstOrDefault(),
                             LastPostTopicId = t.Id,
                             LastPostId = t.LastPostId ?? 0,
                             ForumCategoryId = t.ForumCategoryId,
                             ForumId = t.ForumId
                         }).Take(postQuantity).ToList();
            ConvertTopicsDateToUserTimeZone(ref query);
            return query;
        }
        /// <summary>
        /// Recherche par mot-clefs et nom d'auteurs.
        /// </summary>
        /// <param name="Keywords"></param>
        /// <param name="Authors"></param>
        /// <param name="postQuantity"></param>
        /// <param name="requesterTimeZone"></param>
        /// <returns></returns>
        protected List<TopicResult> SearchByKeywordsAndAuthors(ForumSearchCriteria criteria)
        {
            if (criteria.ResultQuantity == 0) criteria.ResultQuantity = 10000;

            String SearchedAuthors;
            if (criteria.Authors == null)
                SearchedAuthors = String.Empty;
            else
            {
                criteria.Authors = criteria.Authors.ToList().Where(author => author != "false").ToArray();
                SearchedAuthors = String.Join(" ", criteria.Authors);
            }

            List<Int32> forumCategoryAllowed = this.ForumCategoryAllowed;

            var resultId = (from t in db.ForumTopicSet.Include("ForumPostSet")
                            where forumCategoryAllowed.Contains(t.ForumCategory_Id) &
                            (t.LabelForumTopic.Contains(criteria.Keywords) ||
                            t.ForumPostSet.Any(p => p.PostMessage_Message.Contains(criteria.Keywords)) ||
                            t.ForumPostSet.Any(p => SearchedAuthors.Contains(p.PostMessage_Author)))
                            select t.Id);

            var query = (from t in db.vw_ForumLastTopic
                         where resultId.Contains(t.Id)
                         orderby t.CreationDateForumTopic descending
                         select new TopicResult()
                         {
                             Id = t.Id,
                             Label = t.Label,
                             Author = t.Author,
                             NumberHasBeenSeen = t.NumberHasBeenSeen,
                             IsUnlocked = t.IsUnlocked,
                             OrderForumTopic = t.OrderForumTopic,
                             CreationDateForumTopic = t.CreationDateForumTopic,
                             NumberOfPost = t.NumberOfPost ?? 0,
                             LastPostDate = (t.LastPostDate ?? new DateTime()),
                             LastPostAuthor = (from p in db.ForumPostSet where (p.Id == t.LastPostId) select p.PostMessage_Author).FirstOrDefault(),
                             LastPostTopicId = t.Id,
                             LastPostId = t.LastPostId ?? 0,
                             ForumCategoryId = t.ForumCategoryId,
                             ForumId = t.ForumId
                         }).Take(criteria.ResultQuantity).ToList();
            ConvertTopicsDateToUserTimeZone(ref query);
            return query;
        }
    }
}
